package com.swallow.auth.infrastructure.acl.oauth2.ext;

import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.security.oauth2.core.OAuth2AccessToken;
import org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService;
import org.springframework.security.oauth2.server.authorization.OAuth2Authorization;
import org.springframework.security.oauth2.server.authorization.OAuth2TokenType;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;

import java.util.Objects;

/**
 * @author: yangjie.deng@resico.cn
 * @since: 2024-05-15 10:34:34
 * @version: v1.0.0
 * @describe:  为了便于给access_token添加前缀索引,这里需要对数据库存储做倒叙,方便添加前缀索引
 */
public class ExtJdbcOAuth2AuthorizationService extends JdbcOAuth2AuthorizationService {
    public ExtJdbcOAuth2AuthorizationService(JdbcOperations jdbcOperations, RegisteredClientRepository registeredClientRepository) {
        super(jdbcOperations, registeredClientRepository);
    }

    /**
     *  此方法实现了挤下线功能
     *
     * @param authorization 认证相关信息
     */
    public void deleteByAuthInfo(OAuth2Authorization authorization) {
        String sql = "delete from oauth2_authorization where principal_name = ? and id != ? ";
        getJdbcOperations().update(sql, authorization.getPrincipalName(), authorization.getId());
    }


    @Override
    public void save(OAuth2Authorization authorization) {
        OAuth2Authorization build = tokenReverse(authorization);
        super.save(build);
    }

    private static OAuth2Authorization tokenReverse(OAuth2Authorization authorization) {
        if (Objects.isNull(authorization)) {
            return null;
        }

        if (Objects.isNull(authorization.getAccessToken())) {
            return authorization;
        }
        OAuth2Authorization.Token<OAuth2AccessToken> accessToken = authorization.getAccessToken();
        // token 反转
        OAuth2AccessToken newToken = new OAuth2AccessToken(OAuth2AccessToken.TokenType.BEARER,
                                                           doReverse(accessToken.getToken().getTokenValue()),
                                                           accessToken.getToken().getIssuedAt(),
                                                           accessToken.getToken().getExpiresAt(),
                                                           authorization.getAuthorizedScopes()
                                                           );
        // 重新构建token
        return OAuth2Authorization.from(authorization).token(newToken).build();
    }

    @Override
    public OAuth2Authorization findById(String id) {
        OAuth2Authorization authorization = super.findById(id);
        return tokenReverse(authorization);
    }

    @Override
    public OAuth2Authorization findByToken(String token, OAuth2TokenType tokenType) {
        OAuth2Authorization authorization = super.findByToken(doReverse(token), tokenType);
        return tokenReverse(authorization);
    }

    private static String doReverse(String token) {
        String[] split = token.split("\\.");

        StringBuilder reverse = new StringBuilder();
        int start = split.length - 1;

        for (int i = start; i >= 0; i --) {
            reverse.append(split[i]);
            if (i > 0) {
                reverse.append(".");
            }
        }
        return reverse.toString();
    }
}
